﻿#region Copyright Information

// ****************************************************************
// Feel free to extend or modify the code of the application to your needs. 
// But remember do it for the Glory of our Lord Jesus Christ
// ****************************************************************

#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using NLog;
using Presenter.Data;
using Presenter.Interfaces.Persistence;
using Presenter.Model.Properties;

#endregion

namespace Presenter.Model
{
	/// <summary>
	/// Description of MyClass.
	/// </summary>
	public class PersistenceManager : IPersistanceManager
	{
		/// <summary>
		/// Reference to logging tool.
		/// </summary>
		private readonly static Logger logging = LogManager.GetCurrentClassLogger();

		/// <summary>
		/// Holds the configuration file.
		/// </summary>
		private readonly XDocument configuration;

		/// <summary>
		/// Holds all songs.
		/// </summary>
		private readonly List<SongInfo> allSongs;

		/// <summary>
		/// <see cref="PersistenceManager"/> constructor.
		/// </summary>
		/// <param name="configurationPath"></param>
		public PersistenceManager(string configurationPath)
		{
			// Load the configuration file.
			configuration = XDocument.Load(configurationPath);
			// Populate the list of songs.
			allSongs = (from songs in configuration.Root.Elements().AsParallel()
						select new SongInfo(
							Guid.Parse(songs.Attribute(Settings.Default.Id).Value),
							songs.Attribute(Settings.Default.Name).Value,
							(from verses in songs.Elements()
							 select new LyricsInfo(new List<VerseInfo> { new VerseInfo(1, "", VerseType.Verse) }, string.Empty)))).
				ToList();

			/*
			 * int.Parse(verses.Attribute(Settings.Default.Number).Value),
								verses.Attribute(Settings.Default.Text).Value,
								(VerseType)Enum.Parse(typeof(VerseType), verses.Attribute(Settings.Default.Type).Value)
								)))).ToList();
			 */

			logging.Info("Loading the songs from the configuration file.");
		}

		/// <summary>
		/// Returns all the <see cref="SongInfo"/> in the Persistence.
		/// </summary>
		/// <returns><code>List[SongInfo]</code></returns>
		public IEnumerable<SongInfo> GetAll()
		{
			logging.Info("Retrieving the songs.");
			return allSongs.OrderBy(song => song.Name);
		}

		/// <summary>
		/// Returns a song by its name.
		/// </summary>
		/// <param name="name">The name of the song.</param>
		/// <returns>All the information associated with a song.</returns>
		public SongInfo GetSongByName(string name)
		{
			logging.Info("Return a song by its name.");
			return allSongs.First(songName => songName.Name == name);
		}

		/// <summary>
		/// Add a Song to the Persistence.
		/// </summary>
		/// <param name="song">Song name.</param>
		public void AddSong(SongInfo song)
		{
			allSongs.Add(song);
			logging.Info("Add a new song.");
		}

		/// <summary>
		/// Removes a song from the Persistence.
		/// </summary>
		/// <param name="song">Song name.</param>
		public void RemoveSong(string song)
		{
			allSongs.RemoveAll(songName => songName.Name == song);
			logging.Info("Remove the specified song.");
		}

		/// <summary>
		/// Updates a song.
		/// </summary>
		/// <param name="song">The song to pe updated.</param>
		public void UpdateSong(SongInfo song)
		{
			allSongs.RemoveAll(songName => songName.Name == song.Name);
			allSongs.Add(song);
			logging.Info("Update the specified song.");
		}

		/// <summary>
		/// Save the configuration file.
		/// </summary>
		/// <param name="configurationPath">The location to save the file.</param>
		public void Save(string @configurationPath)
		{

			// Remove the content of the file.
			configuration.Root.RemoveAll();
			// Add the new content.
			foreach (var songInfo in allSongs)
			{
				var song = new XElement(Settings.Default.Song);
				song.SetAttributeValue(Settings.Default.Id, songInfo.Id);
				song.SetAttributeValue(Settings.Default.Name, songInfo.Name);
				foreach (var verseElement in songInfo.Verses)
				{
					var verse = new XElement(Settings.Default.Verse);
                    //verse.SetAttributeValue(Settings.Default.Number, verseElement.Number);
                    //verse.SetAttributeValue(Settings.Default.Text, verseElement.Text);
                    //verse.SetAttributeValue(Settings.Default.Type, verseElement.Type);
					song.Add(verse);
				}
				configuration.Root.Add(song);
			}
			// Save the file to disk.

			try
			{
				configuration.Save(@configurationPath);
				logging.Info("Save songs to file.");
			}
			catch (IOException ioException)
			{
				logging.Error("Error " + ioException.Message);
				throw new Exception(ioException.Message);
			}
		}
	}
}